{-# OPTIONS -Wall #-}

--------------------------------------------------------------------------------
-- |
-- Module      :  Majalan.Base.Internal.Beat
-- Copyright   :  (c) Stephen Tetley 2014
-- License     :  BSD3
--
-- Maintainer  :  stephen.tetley@gmail.com
-- Stability   :  unstable
-- Portability :  GHC
--
-- Generate beat patterns
--
--------------------------------------------------------------------------------

module Majalan.Base.Internal.Beat
  (

    Bar(..)
  , GenBeat(..)
  , Division
  , BeatSecs
  , divDuration
  , readDivisions
  , makeBarFromDivisions
    
  ) where


import Majalan.Base.Internal.Base


import Data.Ratio


newtype Bar a = Bar { getBar :: [BeatSecs a] }
  deriving (Eq,Show)


-- | TODO - coupling rest to melody rather than beat pattern may
-- make more musical sense (and simplify the implementation).
--
data GenBeat drn a = GenBeat !drn !a
  deriving (Eq,Show)



type Division a = GenBeat Rational a

type BeatSecs a = GenBeat Seconds a


divDuration :: GenBeat drn a -> drn
divDuration (GenBeat d _) = d
            


readDivisions :: [Rational] -> [Division ()]
readDivisions = foldr fn []
  where
    fn r ac | r >  0    = (GenBeat r ()) : ac
            | otherwise = ac


makeBarFromDivisions :: TimeSig -> BPM -> [Division a] -> Bar a
makeBarFromDivisions ts@(n,_) bpm rs = 
   let beat_len = beatLength ts bpm 
       sdivs    = evalDivision beat_len $ limitDivision n rs
   in Bar sdivs

limitDivision :: Int -> [Division a] -> [Division a]
limitDivision n = step 0 
  where
    rn                                          = fromIntegral n % 1    
    step ac (x:xs) | ac + divDuration x <= rn   = x : step (ac + divDuration x) xs 
    step _  _                                   = []


evalDivision :: Seconds -> [Division a] -> [BeatSecs a]
evalDivision unit_len = map fn 
  where
    fn (GenBeat r a) = GenBeat (unit_len * realToFrac r) a 




